package emby.lang;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import emby.err.InvalidArgumentError;
import emby.err.NoConstructorException;
import emby.err.RuntimeError;
import emby.overload.OverloadCallable;
import emby.util.ReflectionHelp;

public class JavaConstructorWrapper extends EmbyObject implements OverloadCallable, Serializable{

	private static final long serialVersionUID = 6623178462733352054L;
	Constructor<Object>[] consts;
	String constName;
	public JavaConstructorWrapper(Constructor<Object>[] consts){
		this.consts = consts;
		this.constName = consts[0].getName();
	}
	
	public JavaConstructorWrapper(Class clazz){
		this(-1,clazz);
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public JavaConstructorWrapper(int line, Class clazz){
		Constructor[] consts = clazz.getConstructors();
		if(consts.length==0){
			throw new NoConstructorException(line,clazz.getName());
		}
		this.consts = consts;
		this.constName = consts[0].getName();
	}
	@Override
	public Object execute(int lineNumber, Scope s, Object... args) {
		Object o = EmbyNull.Null;
		//Look for the method with the right signature
		Constructor<Object> correctConst = null;
		for( int i = 0; i<consts.length; i++){
			Class<?>[] parameterTypes = consts[i].getParameterTypes();
			if( ReflectionHelp.argsMatch(parameterTypes, args)){
				correctConst= consts[i];
				break;
			}
		}

		if( correctConst==null){
			throw new InvalidArgumentError(lineNumber, "Reflective java call on "+o.getClass()+" has invalid args. Also, emby cannot handle varargs.");
		}

		try {
			correctConst.setAccessible(true);
			o=correctConst.newInstance(args);
		} catch (IllegalArgumentException e) {
			throw new InternalError("Invalid args on JavaConstructorWrapper reflection. (Should not happen: the for loop looks for a matching method)");
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.getTargetException().printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}
		return o;
	}

	public String toString(){
		return "JavaConstructorWrapper:"+constName;
	}
}
